#-*- coding: UTF-8 -*- 
#from uiautomator import device as d
from uiautomator import Device
import uiautomator
import urllib3
import time
from datetime import datetime
import xmlui
import os
from multiprocessing import Pool
import sys, getopt

reload(sys)
sys.setdefaultencoding('utf-8')


class AndroidPhone:
    def __init__(self, serial):
        self.device = None
        if serial != None:
            self.device = Device(serial)
        else:
            self.device = Device()

    def do_cmd(self, *args, **kwargs):
        return self.device.cmd(*args)

    
class AndroidTime:
    def __init__(self, phone):
        date_string = phone.do_cmd('shell', 'date', '+"%Y/%m/%d_%H:%M:%S"').communicate()[0].decode("utf-8").strip().splitlines()[0]
        android_date = datetime.strptime(date_string,"%Y/%m/%d_%H:%M:%S")
        self.shift_date = datetime.now() - android_date
    
    def get_android_time(self):
        t = datetime.now() - self.shift_date
        return t.strftime('%Y-%m-%d %H:%M:%S')


class AndroidView:
    def __init__(self, phone, fd):
        self.clicked_widget = {}
        self.phone = phone
        self.time = AndroidTime(phone)
        self.output_fd = fd
        self.cotput_count = 0

    def output(self, todo, body):
        self.cotput_count = self.cotput_count + 1
        array = []
        body = body.replace('\r', '')
        body = body.replace('\n', '/')
        array.append(str(self.cotput_count))
        array.append(self.time.get_android_time())
        array.append(todo)
        array.append(body)
        output_str = '\t'.join(array)
        
        if self.output_fd:
            self.output_fd.write(output_str)
            self.output_fd.write('\n')
        print output_str
        
    def set_widget_click(self, widget):
        key = widget['text']
        if not self.clicked_widget.has_key(key):
            self.clicked_widget[key] = 0
        self.clicked_widget[key] = self.clicked_widget[key] + 1

    def clear_widget_click(self):
        widget_white_list = [u'确定', u'下一步', u'允许']
        for key in widget_white_list:
            self.clicked_widget[key] = 0

    def is_widget_clicked(self, widget):
        key = widget['text']
        if self.clicked_widget.has_key(key):
            return self.clicked_widget[key]
        return 0

    def get_package_name(self):
        try:
            return self.phone.device.info['currentPackageName']
        except urllib3.exceptions.ReadTimeoutError as e:
            print 'get_package_name', e
            return None

    def start_activity_by_package(self, package_name):
        self.phone.do_cmd('shell', 'monkey', '-p', package_name, '-v ', '1')
        self.output('Start', package_name)
        self.phone.device.wait.update()
        pass

    def start_monkey(self, package_name, t):
        self.output('Monkey', str(t * 30))
        self.phone.do_cmd('shell', 'monkey', '-p', package_name, '-v', '--throttle 100', str(t * 30))
        time.sleep(t)
        pass

    def dump(self, package_name):
        self.phone.device.wait.idle()
        try:
            t = self.phone.device.dump()
            return xmlui.parse(t, package_name)
        except urllib3.exceptions.ReadTimeoutError as e:
            return None

    def click(self, widget):
        if widget.has_key('text'):
            #try:
            self.phone.device.wait.idle()
            w = self.phone.device(className=widget['class'], text=widget['text'])
            attrib = None
            try:
                if w.exists:
                    attrib = w.info
            except (uiautomator.JsonRPCError, urllib3.exceptions.ReadTimeoutError) as e:
                print 'click', e
                return False
            if attrib and attrib.has_key('bounds'):
                bounds = attrib['bounds']
                x = int((int(bounds['left']) + int(bounds['right']))/2)
                y = int(int(bounds['top']) + int(bounds['bottom']))/2
                self.phone.device.click(x, y)
                self.phone.device.wait.update()
                try:
                   gbk = widget['text'].encode("gbk")
                except:
                    gbk = ''
                self.output('Click', gbk)

            else:
                return False
            #except:
            #    print 'click error'
            #    return False
            self.set_widget_click(widget)
        return True

    def finger(self, way):
        try:
            flings = self.phone.device(scrollable='true', enabled='true')
            if len(flings) > 0:
                for fling in flings:
                    if way == 'Up':
                        fling.fling.vert.forward()
                    elif way == 'Down':
                        fling.fling.vert.backward()
                    elif way == 'Left':
                        fling.fling.horiz.forward()
                    elif way == 'Right':
                        fling.fling.horiz.backward()
                self.output('Fling', way)
        except urllib3.exceptions.ReadTimeoutError as e:
            print 'finger', e
            return False
        return True
        
    def key_home(self):
        self.phone.device.press.home()
        self.output('Key', 'Home')
            
    def key_back(self):
        self.phone.device.press.back()
        self.phone.device.wait.update()
        self.output('Key', 'Back')

    
    def auto_test(self, current_package_name, at_time):
        print 'Auto Test Start'
        self.key_home()
        home_package_name = self.get_package_name()
        if home_package_name == current_package_name:
            home_package_name = None
        #d.freeze_rotation()

        op_time = time.clock()

        count = 0
        while(time.clock() - op_time < at_time):
            package_name = self.get_package_name()
            if package_name:
                if home_package_name == package_name:
                    self.start_activity_by_package(current_package_name)
                    
                if current_package_name != package_name:
                    self.key_back()

            widgets = self.dump(self.get_package_name())
            self.clear_widget_click()
            if widgets:
                count = count + 1
                for widget in widgets['clickable']:
                    if self.is_widget_clicked(widget) == 0:
                        if self.click(widget):
                            count = 0
                        else:
                            break

                if count != 0:
                    if count < 3 and widgets['scrollable'] == True:
                        self.finger('Up')
                    elif count < 5:
                        self.key_back()
                    elif count > 10:
                        self.start_monkey(current_package_name, 60)
                        count = 0
                   
def auto_test_thread(serial, package, timeout, output_folder):
    if serial:
        print 'Serial:', serial
    print 'Timeout:', timeout

    phone = AndroidPhone(serial)

    output_fd = None
    if output_folder:
        output_fd = open(os.path.join(output_folder, 'history.txt'), 'w')

    view = AndroidView(phone, output_fd)

    if package == None:
        package = view.get_package_name()

    print 'Package:', package

    view.auto_test(package, timeout)

    print 'OK (1 tests)'

    if output_fd:
        output_fd.close()

def run(serial, package, timeout, output_folder):
    pool = Pool(2)
    result = pool.apply_async(func=auto_test_thread, args=(serial, package, timeout, output_folder))
    pool.close()
    #try:
    result.get(timeout + 120)
    #except:
    #    print 'Auto Test Time Out'
    #    pool.terminate()

if __name__ == "__main__":
    debug = True
    serial = None
    package = None
    timeout = 300
    output_folder = None

    try:
        opts, args = getopt.getopt(sys.argv[1:],"hs:t:p:o:",['serial=', 'timeout=', 'package=', 'output='])
    except getopt.GetoptError:
        print 'main.py [-s <serial>] [-t <timeout>] -p [package] -o [output_folder]'
        sys.exit(2)
    for opt, arg in opts:
        if opt == '-h':
            print 'main.py [-s <serial>] [-t <timeout>] -p [package] -o [output_folder]'
            sys.exit()
        elif opt in ("-s", "--serial"):
            serial = arg
        elif opt in ("-t", "--timeout"):
            timeout = int(arg)
        elif opt in ("-p", "--package"):
            package = arg
        elif opt in ("-o", "--output"):
            output_folder = arg

    if debug:
        auto_test_thread(serial, package, timeout, output_folder)
    else:
        run(serial, package, timeout, output_folder)


    






